package com.micro.magupe.cms.participle;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.DicAnalysis;

import com.micro.magupe.cms.util.ExcelUtils;

/**
 * https://blog.csdn.net/sinat_18091513/article/details/79432754
 * https://blog.csdn.net/buchiyudemao_/article/details/50056691
 * @author magupe
 */
public class TfIdfParticiple {

	// 文档表
    private List<String> documents;
    
    // 文档与词汇列表
    private List<List<String>> documentWords;
    
	// 文档词频统计表
    private List<Map<String,Double>> docuementTfList;
    // 统一文档词频统计表
    private Map<String,Double> docuementTf;
    
    // 词汇出现文档数统计表
    private Map<String,Double>  idfMap;
    
    // 词汇出现文档数统计表
    private Set<String>  set;
    
    public TfIdfParticiple(List<String> documents) {
        this.documents = documents;
        initSet();
    }
    
	public void eval() throws IOException{
        this.splitWord();
        this.calTf();
        this.calIdf();
        //List<Map<String, Double>> tfidfRes = calTfIdf();
        //ExcelUtils.exportExcel(tfidfRes, idfMap, docuementTf);
        Map<String, Double> tfIdf = calTfIdf_();
        ExcelUtils.exportExcel(tfIdf, idfMap, docuementTf);
    }
    
    /**
     * 对每一个文档进行词语切分
     * @author Shaobin.Ou
     */
    public void splitWord() {
        documentWords = new ArrayList<List<String>>();
        for( String document : documents) {
            Result splitWordRes = DicAnalysis.parse(document);
            List<String> wordList = new ArrayList<String>();
            for(Term term : splitWordRes.getTerms()) {
            	if(!set.contains(term.getNatureStr())) {
            		wordList.add(term.getName());
            	}
            }
            documentWords.add(wordList); 
        }
    }
    
    /**
     * 对每一个文档进行词频的计算，即计算每一个词在当前文档中出现的次数
     * @author Shaobin.Ou
     */
    public void calTf() {
        docuementTfList = new ArrayList<Map<String,Double>>();
        for(List<String> wordList : documentWords ) { 
            Map<String,Double> countMap = new HashMap<String,Double>();
            for(String word : wordList) {
                if(countMap.containsKey(word)) {
                    countMap.put(word, countMap.get(word) + 1);
                }else {
                    countMap.put(word, 1.0);
                }
            }
            docuementTfList.add(countMap);
        }
        
        docuementTf = new HashMap<String, Double>();
        for(Map<String, Double> map : docuementTfList) {
        	for(Entry<String, Double> item : map.entrySet()) {
        		if(docuementTf.containsKey(item.getKey())){
        			docuementTf.put(item.getKey(), docuementTf.get(item.getKey()) + item.getValue());
        		} else {
        			docuementTf.put(item.getKey(), item.getValue());
        		}
        	}
        }
    }
    
    /**
     * 计算逆文档频率 IDF
     * @author Shaobin.Ou
     */
    public void calIdf() { 
        int documentCount = getDocumentCount();
        idfMap = new HashMap<String, Double>();
        // 统计词语在多少文档里面出现了
        Map<String,Double> wordAppearendMap = new HashMap<String,Double>();
        for(Map<String, Double> countMap : docuementTfList) {
            for(String word : countMap.keySet()) {
                if(wordAppearendMap.containsKey(word)) {
                    wordAppearendMap.put(word, wordAppearendMap.get(word) + 1);
                }else {
                    wordAppearendMap.put(word, 1.0);
                }
            }
        }
        
        // 对每个词语进行计算
        for(String word : wordAppearendMap.keySet()) {
            double idf = Math.log(documentCount / (wordAppearendMap.get(word) + 1));
            idfMap.put(word, idf);
        }
    }
    
    public Map<String, Double> calTfIdf_() {
    	Map<String, Double> tfIdf = new HashMap<String, Double>();
        for(Entry<String, Double> item : docuementTf.entrySet()) {
        	double tfidf = idfMap.get(item.getKey()) * item.getValue();
        	tfIdf.put(item.getKey(), tfidf);
        }
        return tfIdf;
    }
    
    public List<Map<String,Double>> calTfIdf() {
        List<Map<String, Double>> tfidfRes = new ArrayList<Map<String, Double>>();
        for(Map<String, Double> docuementTfMap : docuementTfList ) {
            Map<String, Double> tfIdf = new HashMap<String, Double>();
            for(String word : docuementTfMap.keySet()) {
                double tfidf = idfMap.get(word) * docuementTfMap.get(word);
                tfIdf.put(word, tfidf);
            }
            tfidfRes.add(tfIdf);
        }
        
        return tfidfRes;
    }
    
    /**
     * 获取所有文档数，用于逆文档频率 IDF 的计算
     * @author Shaobin.Ou
     * @return 所有文档数
     */
    private int getDocumentCount() {
        return documents.size();
    }
    
    private void initSet() {
    	set = new HashSet<String>();
        set.add("w");		
        set.add("x");		
        set.add("xx");		
        set.add("xu");		
        set.add("k");		
        set.add("h");		
        set.add("o");		
        set.add("y");		
        set.add("e");		
        set.add("u");		
        set.add("uzhe");		
        set.add("ule");		
        set.add("uguo");		
        set.add("ude1");		
        set.add("ude2");		
        set.add("ude3");		
        set.add("usuo");		
        set.add("udeng");		
        set.add("uyy");		
        set.add("udh");		
        set.add("uls");		
        set.add("uzhi");		
        set.add("ulian");		
        set.add("e");		
        set.add("e");		
        set.add("e");		
        set.add("c");		
        set.add("cc");		
        set.add("p");		
        set.add("pba");		
        set.add("pbei");		
        set.add("q");		
        set.add("qv");		
        set.add("qt");		
        set.add("m");		
        set.add("mq");		
        set.add("r");		
        set.add("rr");		
        set.add("rz");		
        set.add("rzt");		
        set.add("rzs");		
        set.add("rzv");		
        set.add("ry");		
        set.add("ryt");		
        set.add("rys");		
        set.add("ryv");		
        set.add("rg");		
        set.add("b");		
        set.add("bl");		
        set.add("f");		
        set.add("s");		
        set.add("t");		
        set.add("tg");		
        set.add("vshi");		
        set.add("vyou");		
        set.add("v");		
        set.add("vd");		
        set.add("vf");		
        set.add("vx");		
        set.add("vi");		
        set.add("vl");		
        set.add("vg");		
	}
}
